package suncertify.db;

/**
 * Defines a database file access contract. The database file consists of records, each record consist of fields. The
 * length of the fields in each record are fixed, this yields that the record length is fixed too. Records are
 * identified by their index in the database file, this is represented by the <code>recNo</code> parameter. The record's
 * data is defined by a <code>String[]</code> array. Each record has a metadata flag that represents it's state, the
 * record is either deleted or not deleted.
 * 
 * <p>
 * The records in the database file can be read, updated and deleted. Records are deleted by changing their metadata
 * flag to deleted, the physical space for the record is unchanged. New records are either appended to the end of the
 * database file or use the deleted records space caused by delete operations.
 * 
 * <p>
 * The data access is assumed to take place in a multithreaded environment, multiple clients can read, update or delete
 * any record at the same time in the database. The interface provides a serialization mechanism to ensure that a record
 * can be updated or deleted by one client only at a time, this is done using the lock/unlock cookie that is intended to
 * be used as follows:
 * <ol>
 * <li>Before a record can be updated or deleted it must be locked by calling the {@link #lockRecord(long)} function,
 * this function returns a cookie if the record is not already locked by another client. The lock cookie is a unique
 * value that identifies this record to be locked (owned) by a specific client. While the record is locked no other
 * client can lock the same record.</li>
 * <li>The client uses the lock cookie to either update or deleted the record.</li>
 * <li>After the client updates or deletes the record it must call the {@link #unlock(long, long)} method, this function
 * removes the lock and makes the record available for other clients to lock.</li>
 * </ol>
 * 
 * Notes:
 * <ul>
 * <li>Attempting to lock a record that is already locked by another client, causes the thread executing the call to
 * give up CPU cycles and wait until the record is unlocked.</li>
 * <li>The interface relies on the clients to call the unlock method! if a client forgets to unlock a record then he/she
 * might block other clients who try to lock the same record.</li>
 * </ul>
 * 
 */
public interface DBAccess {

    /**
     * Definition for a function that reads a record from the database file. Returns an array where each element is a
     * record value.
     * 
     * @param recNo
     *            The index of the record in the file.
     * @return An array where each element is a record value.
     * @throws RecordNotFoundException
     *             Thrown if the <code>recNo</code> does not exists or is marked as empty in the database file.
     */
    public String[] readRecord(long recNo) throws RecordNotFoundException;

    /**
     * Definition for a function that modifies the fields of a record. The new value of field n appears in data[n].
     * 
     * @param recNo
     *            The index of the record in the file.
     * @param data
     *            A string array where each element represents a record value.
     * @param lockCookie
     *            The lock cookie that was provided by {@link #lockRecord(long)}.
     * @throws RecordNotFoundException
     *             Thrown if the <code>recNo</code> does not exists or is marked as empty in the database file.
     * @throws SecurityException
     *             Thrown when the <code>recNo</code> is locked with a cookie other than <code>lockCookie</code>
     */
    public void updateRecord(long recNo, String[] data, long lockCookie) throws RecordNotFoundException,
	    SecurityException;

    /**
     * Definition for a function that deletes a record in the database file, making the record number and associated
     * disk storage available for reuse.
     * 
     * @param recNo
     *            The index of the record in the file.
     * @param lockCookie
     *            The lock cookie that was provided by {@link #lockRecord(long)}.
     * @throws RecordNotFoundException
     *             Thrown if the <code>recNo</code> does not exists or is marked as empty in the database file.
     * @throws SecurityException
     *             Thrown when the <code>recNo</code> is locked with a cookie other than <code>lockCookie</code>
     */
    public void deleteRecord(long recNo, long lockCookie) throws RecordNotFoundException, SecurityException;

    /**
     * Definition for a function that returns an array of record numbers that match the specified criteria. Field n in
     * the database file is described by criteria[n]. A null value in criteria[n] matches any field value. A non-null
     * value in criteria[n] matches any field value that begins with criteria[n]. (For example, "Fred" matches "Fred" or
     * "Freddy".)
     * 
     * @param criteria
     *            The find criteria.
     * @return An array of record numbers that match the specified criteria.
     */
    public long[] findByCriteria(String[] criteria);

    /**
     * Definition for a function that creates a new record in the database (possibly reusing a deleted entry). Inserts
     * the given data, and returns the record number of the new record.
     * 
     * @param data
     *            A string array where each element represents a record value.
     * @return The record number of the new record.
     * @throws DuplicateKeyException
     *             Thrown if the <code>data</code> values already exist in the database.
     */
    public long createRecord(String[] data) throws DuplicateKeyException;

    /**
     * Definition for a function that locks the record so that it can only be updated or deleted by this client.
     * Returned value is a cookie that must be used when the record is unlocked, updated, or deleted. If the specified
     * record is already locked by a different client, the current thread gives up the CPU and consumes no CPU cycles
     * until the record is unlocked.
     * 
     * @param recNo
     *            The number of the record in the file.
     * @return A cookie that must be used when the record is unlocked, updated, or deleted
     * @throws RecordNotFoundException
     *             Thrown if the <code>recNo</code> does not exists or is marked as empty in the database file.
     */
    public long lockRecord(long recNo) throws RecordNotFoundException;

    /**
     * Definition for a function that releases the lock on a record. Cookie must be the cookie returned when the record
     * was locked; otherwise throws SecurityException.
     * 
     * @param recNo
     *            The index of the record in the file.
     * @param cookie
     *            The lock cookie that was provided by {@link #lockRecord(long)}.
     * @throws SecurityException
     *             Thrown when the <code>recNo</code> is locked with a cookie other than <code>cookie</code>
     */
    public void unlock(long recNo, long cookie) throws SecurityException;
}
